import re
from django.urls import reverse
from random import randint

from django.contrib.auth import login, authenticate
from django.http import HttpResponseBadRequest, HttpResponse, JsonResponse, HttpResponseRedirect
from django.shortcuts import render, redirect
from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin

from code_two.urls import logger
from logs.captcha.captcha import captcha
from django_redis import get_redis_connection
from libs.yuntongxun.sms import CCP
from polls.models import User
from utils.response_code import RETCODE
from django.contrib.auth import authenticate
from django.contrib.auth import logout
import json


class RegisterView(View):
    def get(self, requset):
        return render(requset, "register.html")

    def post(self, request):
        mobile = request.POST.get('mobile')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        sms_code = request.POST.get('sms_code')
        if not all([mobile, password2, password, sms_code]):
            return HttpResponseBadRequest('不齐')
            # 2-2、手机号格式是否正确
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return HttpResponseBadRequest('手机号码格式不正确')
        # 2-3、密码是否符合格式
        if not re.match(r'^[0-9a-zA-Z]{8,20}$', password) or not re.match(r'^[0-9a-zA-Z]{8,20}$', password2):
            return HttpResponseBadRequest('密码长度、格式不正确。长度8-20，必须是数字、字母')
        # 2-4、密码和确认密码是否一致
        if password != password2:
            return HttpResponseBadRequest('两次输入的密码不一致')
        redis_conn = get_redis_connection()
        redis_sms_code = redis_conn.get('sms:%s' % mobile)
        if redis_sms_code is None:
            return HttpResponseBadRequest('短信验证码错误')
        user = User.objects.create_user(username=mobile, mobile=mobile, password=password)
        # return HttpResponse('注册成功')
        # return redirect(reverse('home:index'))

        login(request, user)
        resp = redirect(reverse('home:index'))
        resp.set_cookie('is_login', True)
        resp.set_cookie('login_name', user.username)
        return resp


class ImageView(View):
    def get(self, request):
        uuid = request.GET.get('uuid')
        # 2、判断uuid失分获取到
        if uuid is None:
            return HttpResponseBadRequest('没有获取到uuid')
        # 3、通过调用captcha来生成图片验证码（返回：图片内容和图片二进制）
        txt, image = captcha.generate_captcha()
        # 4、将图片内容保存到redis中。uuid作为key，图片内容作为值，同时还需要设置一个过期时间
        redis_conn = get_redis_connection('default')
        # name:数据key，这里采用img前缀：uuid
        # time:300秒后过期
        # value：对应key的值
        redis_conn.setex(name='img:%s' % uuid, time=300, value=txt)
        # 5、返回图片给前端
        return HttpResponse(image, content_type='image/jpeg')


class SmscodeView(View):
    def get(self, request):
        mobile = request.GET.get('mobile')
        image_code = request.GET.get('image_code')
        uuid = request.GET.get('uuid')
        if not all([mobile, image_code, uuid]):
            return JsonResponse({"code": RETCODE.NECESSARYPARAMERR, "errmsg": '参数不齐'})
        redis_conn = get_redis_connection()
        image_code_redis = redis_conn.get('img:%s' % uuid)
        if image_code_redis is None:
            return JsonResponse({"code": RETCODE.IMAGECODEERR, "errmsg": '图片验证码不存在'})
        redis_conn.delete('img:%s' % uuid)
        if image_code != image_code_redis.decode().lower():
            return JsonResponse({"code": RETCODE.IMAGECODEERR, "errmsg": '图片验证码错误'})

        # 3、生成短信验证码：生成6位数验证码
        sms_code = '%06d' % randint(0, 999999)
        ccp = CCP()
        ccp.send_template_sms('13092921608', ['sms_code', 5], 1)
        print(f'你的验证码是：{sms_code}')
        # 4、保存短信验证码内容到redis中,保存时间1分钟
        redis_conn.setex('sms:%s' % mobile, 60, sms_code)
        return JsonResponse({"code": RETCODE.OK, "errmsg": '短信发送成功'})


class LoginView(View):
    def get(self,request):
        return render(request,'login.html')

    def post(self, request):
        mobile = request.POST.get('mobile')
        password = request.POST.get('password')
        remember = request.POST.get('remember')
        # 2、验证参数
        # 参数是否齐全
        if not all([mobile, password]):
            return render(request, 'login.html', {'msg':'参数不齐'})
        # 2 - 1、手机号码是否符合规则
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return render(request, 'login.html', {'msg':'手机号码格式不正确'})
        # 2 - 2、密码是否符合规则
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return render(request, 'login.html', {'msg':'密码格式不正确'})
        #
        # 3、用户认证登录
        # 采用系统自带的认证方法进行认证
        # 如果用户名和密码正确，会返回user，否则返回None
        # 默认的认证方法是：针对于username字段进行用户名的判断。当前的判断信息是“手机号”，所以我们需要修改一下认证字段。我们需要到User模型中进行修改，等测试出现问题的时候，我们再修改
        return_user = authenticate(mobile=mobile, password=password)
        # 如果账号密码验证通过，那么返回有数据的用户信息，否则返回None
        # if return_user is None:
        #     return HttpResponseBadRequest('用户名或密码错误')
        # # 4、状态保持
        login(request, return_user)
        # 5、根据用户选择的是否记住登录状态进行判断
        # 6、设置cookie信息，为首页显示服务
        next_page = request.GET.get('next')
        if next_page:
            resp = redirect(next_page)
        else:
            resp = redirect(reverse('home:index'))
        if remember != 'on':  # 没有记住用户信息
            # 浏览器关闭之后过期
            request.session.set_expiry(0)
            resp.set_cookie('is_login', True)
            u = json.dumps(return_user.username)
            resp.set_cookie('login_name', u)
        else:  # 记住用户信息
            # 默认过期时间。其实使用了全局的过期时间。2周
            request.session.set_expiry(None)
            resp.set_cookie('is_login', True, max_age=24 * 3600 * 14)
            u = json.dumps(return_user.username)
            resp.set_cookie('login_name', u, max_age=24 * 3600 * 14)
        # 7、跳转到首页
        return resp


class LogoutView(View):
    def get(self, request):
        '''
        实现思路：
        1、清楚session数据
        2、删除cookie数据
        3、跳转到首页
        :param request:
        :return:
        '''
        # 实现思路：
        # 1、清楚session数据
        logout(request)
        # 2、删除cookie数据
        resp = redirect(reverse('home:index'))
        resp.delete_cookie('is_login')
        resp.delete_cookie('login_name')
        return resp


class ForgetPasswordView(View):
    def get(self, request):
        return render(request, 'forget_password.html')

    def post(self, request):
        '''
        实现思路：
        1、接收数据
        2、验证数据
            2-1、判断参数是否齐全
            2-2、手机号是否符合规则
            2-3、判断密码是否符合规则
            2-4、判断确认密码是否一致
            2-5、判断短信验证码是否正确
        3、根据手机号码进行用户信息的查询
        4、如果手机号查询出用户信息则进行用户密码的修改
        5、如果手机号没有查询出用户信息，则进行新用户的创建
        6、进行页面跳转，跳转到登录页面
        7、返回响应
        :param request:
        :return:
        '''
        # 1、接收数据
        mobile = request.POST.get('mobile')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        sms_code = request.POST.get('sms_code')
        # 2、验证数据
        #     2-1、判断参数是否齐全
        if not all([mobile, password, password2, sms_code]):
            return HttpResponseBadRequest('缺少必要的参数')
        #     2-2、手机号是否符合规则
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return HttpResponseBadRequest('手机格式不正确')
        #     2-3、判断密码是否符合规则
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return HttpResponseBadRequest('密码格式不正确')
        #     2-4、判断确认密码是否一致
        if password != password2:
            return HttpResponseBadRequest('两次密码输入不一致')
        #     2-5、判断短信验证码是否正确
        redis_conn = get_redis_connection('default')
        redis_sms_code = redis_conn.get('sms:%s' % mobile)
        if redis_sms_code is None:
            return HttpResponseBadRequest('短信验证码过期')
        try:
            if redis_sms_code.decode() != sms_code:
                return HttpResponseBadRequest('验证码错误')
        except Exception as e:
            logger.error(e)
            return HttpResponseBadRequest('验证码错误')
        # 3、根据手机号码进行用户信息的查询
        return_user = User.objects.filter(mobile=mobile).first()
        # 4、如果手机号查询出用户信息则进行用户密码的修改
        # 5、如果手机号没有查询出用户信息，则进行新用户的创建
        if return_user is None:
            try:
                User.objects.create_user(username=mobile, mobile=mobile, password=password)
            except Exception as e:
                logger.error(e)
                return HttpResponseBadRequest('注册失败')
        else:
            try:
                # 调用系统user对象的set_password()进行修改密码，该方法会对密码进行加密
                return_user.set_password(password)
                return_user.save()
            except Exception as e:
                logger.error(e)
                return HttpResponseBadRequest('修改密码失败')
        # 6、进行页面跳转，跳转到登录页面
        resp = redirect(reverse('polls:login'))
        # 7、返回响应
        return resp


class UserCenterView(LoginRequiredMixin, View):
    def get(self, request):
        # 获取已经登录用户的信息
        userinfo = request.user
        context = {
            'username': userinfo.username,
            'mobile': userinfo.mobile,
            'avatar': userinfo.avatar.url if userinfo.avatar else None,
            'user_desc': userinfo.user_desc
        }
        return render(request, 'usercenter.html', context=context)

    def post(self, request):
        '''
        实现思路：
        1、接收用户参数
        2、将用户参数更新到数据库
        3、更新cookie中的username
        4、刷新当前页面（重定向操作）
        5、返回相应
        :param request:
        :return:
        '''
        # 获取已经登录用户的信息
        userinfo = request.user
        # 1、接收用户参数
        # 获取用户提交的用户名，如果没有就将已登录的用户名赋值
        username = request.POST.get('username', userinfo.username)
        # 获取用户提交的介绍，如果没有就将已登录的介绍赋值
        user_desc = request.POST.get('desc', userinfo.user_desc)
        # 获取用户头像(如果没有图片保存地址，则会默认保存到项目的根目录下。否则需要在settting中进行配置地址)
        avatar = request.FILES.get('avatar')
        # 2、将用户参数更新到数据库
        try:
            userinfo.username = username
            userinfo.user_desc = user_desc
            if avatar:
                userinfo.avatar = avatar
            userinfo.save()
        except Exception as e:
            logger.error(e)
            return HttpResponseBadRequest('修改用户信息失败')
        # 3、更新cookie中的username
        # 4、刷新当前页面（重定向操作）
        resp = redirect(reverse('polls:usercenter'))
        u = json.dumps(username)
        resp.set_cookie('login_name', u)
        # 5、返回相应
        return resp


from home.models import *


class WriteBlogView(View):
    def get(self, requset):
        contxt = ArticleCategory.objects.all()
        return render(requset, 'writeblog.html', context={'list': contxt})

    def post(self, request):
        '''
        实现思路：
        1、接收数据
        2、验证数据
        3、数据入库
        4、跳转到指定页面
        :param request:
        :return:
        '''
        # 1、接收数据
        avatar = request.FILES.get('avatar')
        title = request.POST.get('title')
        category_id = request.POST.get('category')
        tags = request.POST.get('tags')
        sumary = request.POST.get('sumary')
        content = request.POST.get('content')
        user = request.user
        # 2、验证数据
        # 2-1、参数齐全验证
        if not all([avatar, title, category_id, sumary, content]):
            return HttpResponseBadRequest('参数不齐全')
        # 2-2、判断分类id
        try:
            category = ArticleCategory.objects.filter(pk=category_id).first()
        except ArticleCategory.DoesNotExist:
            return HttpResponseBadRequest('没有该分类信息')
        # 3、数据入库
        try:
            Article.objects.create(
                author=user,
                avatar=avatar,
                category=category,
                tags=tags,
                sumary=sumary,
                content=content,
                title=title
            )

        except Exception as e:
            logger.error(e)
            return HttpResponseBadRequest('发布失败，请稍后重试')
        # 4、跳转到指定页面
        return redirect(reverse('home:index'))
